﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net.Sockets;  //套接字的命名空间
using System.Net; //IPAddress的命名空间
using System.Threading;
using System.Text;
using UnityEditor;
//using System.Diagnostics.Eventing.Reader;

[RequireComponent(typeof(AudioSource))]
public class WebReaderNeuralNet : MonoBehaviour
{
    public string hostName = "localhost";//8pl021df87.vicp.fun
    public int hostPort = 6000;//45167

    private ArrayList files;
    HashSet<string> oldurls;
    WWW www;
    public Texture2D img, imgProg;
    private string text, outext;
    private int pos;
    private string cururl;
    private int wpos;
    private int lastch;
    private float imgOffsetX;
    private float imgOffsetY;
   
    public void Awake()
    {
        outext = "你好！";
        files = new ArrayList();
        oldurls = new HashSet<string>();
        files.Add("http://www.hao123.com/");
        files.Add("http://www.baidu.com/");
        files.Add("http://www.csdn.net/");
        files.Add("http://www.baidu.com/s?wd=%E9%81%93%E6%95%99");

        //if(Directory.Exists(Server.MapPath("a")))
        //{
        //    //所有子文件夹
        //    foreach(string item in Directory.GetDirectories(Server.MapPath("a")))
        //    {
        //        Response.Write("<b>文件夹：" + item + "</b><br/>");
        //        DirectoryInfo directoryinfo = new DirectoryInfo(item);
        //        Response.Write("名称：" + directoryinfo.Name + "<br/>");
        //        Response.Write("路径：" + directoryinfo.FullName + "<br/>");
        //        Response.Write("创建时间：" + directoryinfo.CreationTime + "<br/>");
        //        Response.Write("上次访问时间：" + directoryinfo.LastAccessTime + "<br/>");
        //        Response.Write("上次修改时间：" + directoryinfo.LastWriteTime + "<br/>");
        //        Response.Write("父文件夹：" + directoryinfo.Parent + "<br/>");
        //        Response.Write("所在根目录：" + directoryinfo.Root + "<br/>");
        //        Response.Write("<br/>");
        //    }

        //    //所有子文件
        //    foreach (string item in Directory.GetFiles(Server.MapPath("a")))
        //    {
        //        Response.Write("<b>文件：" + item + "</b><br/>");
        //        FileInfo fileinfo = new FileInfo(item);
        //        Response.Write("名称：" + fileinfo.Name + "<br/>");
        //        Response.Write("扩展名：" + fileinfo.Extension +"<br/>");
        //        Response.Write("路径：" + fileinfo.FullName +"<br/>");
        //        Response.Write("大小：" + fileinfo.Length +"<br/>");
        //        Response.Write("创建时间：" + fileinfo.CreationTime +"<br/>");
        //        Response.Write("上次访问时间：" + fileinfo.LastAccessTime +"<br/>");
        //        Response.Write("上次修改时间：" + fileinfo.LastWriteTime +"<br/>");
        //        Response.Write("所在文件夹：" + fileinfo.DirectoryName +"<br/>");
        //        Response.Write("文件属性：" + fileinfo.Attributes +"<br/>");
        //        Response.Write("<br/>");
        //    }
        //}

        
    }

    // Use this for initialization
    public void Start()
    {
        //string str = "";
        //for (int i = 20; i < '\u007E'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集：" + str);
        //str = "";
        //for (int i = 3000; i < '\u303F'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集：" + str);
        //str = "";
        //for (int i = 3400; i < '\u4DBF'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集：" + str);
        //str = "";
        //for (int i = '\u4E00'; i < '\u9FFF'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集：" + str);
        //str = "";
        //for (int i = 20000; i < 20000 + '\uA6DF'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集：" + str);
        //str = "";
        //for (int i = '\uFF00'; i < '\uFFEF'; i++)
        //{
        //    str += (char)i;
        //}
        //Debug.Log("字符集："+str);
        Thread bgThread = new Thread(ThreadBackGround);
        bgThread.IsBackground = true;
        bgThread.Start();

        //Debug.Log("字体纹理："+readableFontTexture.width+"x"+readableFontTexture.height);
    }

    public Texture2D GetFontImage(char ch)
    {
        if (fontMap.Contains(ch))
        {
            return (Texture2D)fontMap[ch];
        }
        else
        {
            Texture2D t2d = new Texture2D(112, 128);
            string filename = "/Font/SIMHEI/" + ch + ".jpg";
            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                filename = "D:" + filename;
            }
            if (Application.platform == RuntimePlatform.WindowsPlayer)
            {
                filename = "." + filename;
            }
            FileStream fs = null;
            bool suc = false;
            try
            {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                fs.Seek(0, SeekOrigin.Begin);//游标的操作，可有可无
                byte[] bytes = new byte[fs.Length];//生命字节，用来存储读取到的图片字节
                fs.Read(bytes, 0, bytes.Length);//开始读取，这里最好用trycatch语句，防止读取失败报错
                suc = t2d.LoadImage(bytes);
                
            }
            catch (Exception e)
            {
                Debug.LogWarning(e);
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
            outext += ("\nLoad Font： " + filename + "  " + suc);
            fontMap.Add(ch, t2d);
            return t2d;
        }
    }

    Hashtable fontMap = new Hashtable();
    GameObject go;
    Texture2D rft = null;
    IEnumerator HandleWWWRequest(string url, System.Action<WWW> onSuccess)
    {
        url = url.Replace("https", "http");
        Debug.Log("Request URL: " + url);
        WWW www = new WWW(url);
        
        yield return www;
        if (string.IsNullOrEmpty(www.error))
        {
            onSuccess(www);
        }
        else
        {
            cururl = null;
            Debug.LogWarning("WWW request returned an error: " + www.error);
        }
    }
    bool open = false;
    string flag = "";
    // Update is called once per frame
    public void Update()
    {
        if (www == null)
        {
            if (cururl == null && files.Count > 0)
            {
                int i = new System.Random().Next(0, files.Count);
                cururl = (string)files[i];
                oldurls.Add(cururl);
                files.RemoveAt(i);
                StartCoroutine(HandleWWWRequest(cururl, (w) =>
                {
                    www = w;
                    Debug.Log("Load Url: " + cururl);
                }));
            }
        }
        else if (www.progress >= 1f)
        {
            if (text == null)
            {
                text = www.text;
                parseUrls(text);
               
                
            }
            else
            {
                if (pos < text.Length)
                {
                    char ch = text[pos++];
                    
                    if (open)
                    {
                        if (ch == '>')
                        {
                            Debug.Log("flag: " + flag);
                            flag = "";
                            open = false;
                            
                        }
                        else if (ch == ' ')
                        {
                            pos = text.IndexOf('>', pos);
                            if (pos == -1)
                            {
                                pos = text.Length;
                            }
                            Debug.Log("flag: "+flag);
                        }
                        else
                        {
                            flag += ch;
                        }
                        //if (flag.StartsWith("body"))
                        //{
                        //    body = true;
                        //    Debug.Log("body");
                        //}
                        if (flag.StartsWith("script") || flag.StartsWith("style") || flag.StartsWith("span"))
                        {
                            Debug.Log("跳过："+flag);
                            pos = text.IndexOf('<', pos);
                            if (pos == -1)
                            {
                                pos = text.Length;
                            }
                            flag = "";
                            open = false;
                            return;
                        }
                    } else
                    if (ch == '<')
                    {
                        open = true;
                    }
                    else
                    if (ch == '>')
                    {
                        open = false;
                    }
                    else
                    if (!open && ch > 0)
                    {
                        //if (!body)
                        //{
                        //    pos = text.IndexOf('<', pos);
                        //    if (pos == -1)
                        //    {
                        //        pos = text.Length;
                        //    }
                        //    return;
                        //}
                        if (clientSocket == null || clientSocket.Connected == false)
                        {
                            pos--;
                            return;
                        }
                        MemoryStream stream = new MemoryStream();
                        BinaryWriter w = new BinaryWriter(stream);
                        w.Write(0);
                        w.Write((short)1002);
                        w.Write((byte)1);//左脑
                        w.Write((short)128+64);
                        w.Write((short)0);


                        MemoryStream stream2 = new MemoryStream();
                        BinaryWriter w2 = new BinaryWriter(stream2);
                        w2.Write(0);
                        w2.Write((short)1002);
                        w2.Write((byte)2);//右脑
                        w2.Write((short)128 + 64);
                        w2.Write((short)0);

                        Texture2D t2d = GetFontImage(ch);
                        int charWidth, charHeight;// 字符宽高

                        charWidth = t2d.width;
                        charHeight = t2d.height;

                        w.Write((short)charWidth);
                        w.Write((short)charHeight);

                        w2.Write((short)charWidth);
                        w2.Write((short)charHeight);

                        for (int i = 0; i < charWidth; i++)
                        {
                            for (int j = 0; j < charHeight; j++)
                            {
                                var color = t2d.GetPixel(i, j);

                                int v = 0;
                                v += ((int)(color.r * 255)) << 16;
                                v += ((int)(color.g * 255)) << 8;
                                v += ((int)(color.b * 255));
                                w.Write((short)v);
                                w2.Write((short)v);

                            }
                        }
                        long p = w.BaseStream.Position;
                        w.BaseStream.Position = 0;
                        w.Write((int)p);
                        w.BaseStream.Position = p;

                        SendToServer(stream);

                        p = w.BaseStream.Position;
                        w2.BaseStream.Position = 0;
                        w2.Write((int)p);
                        w2.BaseStream.Position = p;

                        SendToServer(stream2);

                    }
                    lastch = ch;
                }
                else
                {
                    www = null;
                    cururl = null;
                    text = null;
                    pos = 0;
                    wpos = 0;
                    lastch = 0;
                    //body = false;
                    open = false;
                    flag = "";
                }
            }
        }
        else
        {

        }
    }

    private void parseUrls(string text)
    {
        int i = 0;
        while ((i = text.IndexOf("href=\"", i + 1)) != -1)
        {
            int end = text.IndexOf("\"", i + 6);
            if (end == -1)
            {
                continue;
            }
            string u = text.Substring(i + 6, end - i - 6);
            if (u.StartsWith("/"))
            {
                u = cururl.Substring(0, cururl.LastIndexOf("/")) + u;
            }
            if (files.Contains(u) == false && oldurls.Contains(u) == false)
            {
                files.Add(u);
                Debug.Log(u);
            }
        }
    }

    void OnGUI()
    {
        float imgWidth = 50f;
        GUI.Label(new Rect(5f, 5f, 200f, 200f), "Pos: " + pos);
        GUI.DrawTexture(new Rect((Screen.width - imgProg.width) / 2f, 10f, imgProg.width * (www != null ? www.progress : 0f), imgProg.height * 1f), imgProg);
        float y = 20f;
        if (text != null)
        {
            GUI.TextArea(new Rect(5f, y, Screen.width - 10f, Screen.height / 2 - y - 25f), text.Substring(pos, Math.Min(1024, text.Length - pos)));
        }
        if (outext != null)
        {
            GUI.TextArea(new Rect(5f, y + (Screen.height / 2), Screen.width - 10f, Screen.height / 2 - y - 35f), outext.Substring(0, Math.Min(1024, outext.Length)));
        }
        if (clientSocket != null && clientSocket.Connected)
        {
            GUI.DrawTexture(new Rect((Screen.width - imgWidth) / 2f + imgOffsetX, (Screen.height - imgWidth) / 2f + imgOffsetY, imgWidth, imgWidth), img);
        }
        
    }

   /**
   * path：文件创建目录
   * name：文件的名称
   *  info：写入的内容
   */
    void CreateFile(string path, string name, string info)
    {
        //文件流信息
        StreamWriter sw;
        FileInfo t = new FileInfo(path + "//" + name);
        if (!t.Exists)
        {
            //如果此文件不存在则创建
            sw = t.CreateText();
        }
        else
        {
            //如果此文件存在则打开
            sw = t.AppendText();
        }
        //以行的形式写入信息
        sw.WriteLine(info);
        //关闭流
        sw.Close();
        //销毁流
        sw.Dispose();
    }

    /**
   * path：读取文件的路径
   * name：读取文件的名称
   */
    ArrayList LoadFile(string path, string name)
    {
        //使用流的形式读取
        StreamReader sr = null;
        try
        {
            sr = File.OpenText(path + "//" + name);
        }
        catch (Exception e)
        {
            //路径与名称未找到文件则直接返回空
            return null;
        }
        string line;
        ArrayList arrlist = new ArrayList();
        while ((line = sr.ReadLine()) != null)
        {
            //一行一行的读取
            //将每一行的内容存入数组链表容器中
            arrlist.Add(line);
        }
        //关闭流
        sr.Close();
        //销毁流
        sr.Dispose();
        //将数组链表容器返回
        return arrlist;
    }

    /**
   * path：删除文件的路径
   * name：删除文件的名称
   */

    void DeleteFile(string path, string name)
    {
        File.Delete(path + "//" + name);

    }


    //1.1创建套接字
    Socket clientSocket = null;
    Thread clientThread = null;
    IPHostEntry hostAddr = null;
    //连接服务器
    private bool ConnectHostStart(string hostName, int port)
    {
        //1.2
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//地址类型，数据传输方式，协议
        try
        {
            if (hostAddr == null)
            {
                hostAddr = Dns.GetHostEntry(hostName);
            }
            for (int i = hostAddr.AddressList.Length - 1; i >= 0; i--)
            {
                Debug.Log("与服务器"+hostAddr.AddressList[i].ToString()+":"+port+"连接中...");
                //3与服务器建立连接
                IPAddress address = hostAddr.AddressList[i];
                //2.2 设置IP地址和端口号
                IPEndPoint endPoint = new IPEndPoint(address, port);
                try
                {
                    clientSocket.Connect(endPoint); // 与服务器连接
                    Debug.Log("与服务器连接成功！");
                    //4.接收或发送消息 使用线程来实现
                    clientThread = new Thread(ReceiveMsg);
                    clientThread.IsBackground = true; //开启后台线程
                    clientThread.Start();
                    return true;
                }
                catch (Exception ex)
                {
                    Debug.Log("连接失败：" + ex.Message);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.Log("连接失败：" + ex.Message);
        }
        return false;
    }
    //连接服务器
    private bool ConnectIpStart(string ipAddress, int port)
    {
        //1.2
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//地址类型，数据传输方式，协议

        Debug.Log("与服务器"+ipAddress+":"+port+"连接中...");
        //3与服务器建立连接
        //2.2 设置IP地址和端口号
        IPAddress address = IPAddress.Parse(ipAddress);
        IPEndPoint endPoint = new IPEndPoint(address, port);
        try
        {
            clientSocket.Connect(endPoint); // 与服务器连接
            Debug.Log("与服务器连接成功！");
            //4.接收或发送消息 使用线程来实现
            clientThread = new Thread(ReceiveMsg);
            clientThread.IsBackground = true; //开启后台线程
            clientThread.Start();
            return true;
        }
        catch (Exception ex)
        {
            Debug.Log("连接失败：" + ex.Message);
        }
        return false;
    }

    private void ReceiveMsg()
    {
        byte[] recBuffer = new byte[1024 * 1024 * 2];//声明最大字符内存
        MemoryStream ms = new MemoryStream(recBuffer, 0, recBuffer.Length);
        BinaryReader br = new BinaryReader(ms);
        int length = 0, len = 0, blen = 0;
        while (serverRuning)
        {
            try
            {
                do
                {
                    br.BaseStream.Position = 0;
                    ms.Position = 0;
                    len = clientSocket.Receive(recBuffer, length, recBuffer.Length - length, SocketFlags.None);
                    length += len;
                } while (length > 4 && (blen = br.ReadInt32()) > length);
                ms.SetLength(blen);
                br.BaseStream.SetLength(blen);
            }
            catch (SocketException ex)
            {
                Debug.LogWarning("Socket异常：" + ex.Message);
                break;
            }
            catch (Exception ex)
            {
                Debug.LogWarning("与服务器断开连接："+ex.ToString());
                break;
            }
            if (len <= 0)
            {
                Debug.LogWarning("与服务器断开连接："+len);
                break;
            }
            //接收到消息
            if (blen > 4)
            {
                //string msg = Encoding.Default.GetString(recBuffer, 0, length);//转译字符串(字符串，开始的索引，字符串长度)
                //string str = $"{DateTime.Now}【接收】{length}bytes";//接收的时间，内容，换行
                //Debug.Log(str);//添加到文本
                try
                {
                    HandleClientRevMsg(br);
                }
                catch (Exception ex)
                {
                    Debug.LogError("客户端异常：" + blen + ", " + ex.ToString());
                    break;
                }
            }
            else
            {
                blen = 4;
            }
            for (int i = 0; i < length - blen; i++)
            {
                recBuffer[i] = recBuffer[blen + i];
            }
            length -= blen;
            if (length < 0)
            {
                length = 0;
            }
        }
        clientSocket.Close();
    }

    private void HandleClientRevMsg(BinaryReader br)
    {

        int id = br.ReadInt16();
        //Debug.Log("【消息】"+id+" - "+br.BaseStream.Length);

        switch (id)
        {
            case 1000:// 神经元兴奋输出
                int t = br.ReadByte();//1左脑 2右脑
                char outchar = ' ';
                //Debug.Log("兴奋输出 "+t+"  "+r.BaseStream.Length);
                for (int i = 0; br.BaseStream.Position + 6 < br.BaseStream.Length; i++)
                {
                    int ox = br.ReadInt16();
                    int oy = br.ReadInt16();
                    int ov = br.ReadInt16();
                    //Debug.Log("兴奋输出 " + t+"  ox"+ox+", oy"+oy+", v"+ov);
                    if (t == 1)
                    {
                        if (oy == 0)
                        {
                            outchar += (char)(ov % 127);
                        }
                    }
                    if (t == 2)
                    {
                        if (oy == 0)
                        {
                            outchar += (char)(ov % 127);
                        }
                    }
                }
                outchar %= (char)127;
                //Debug.Log("Output: "+ch);
                outext = outext.Insert(outext.Length, "" + outchar);
                if (outext.Length > 1024)
                {
                    outext = outext.Remove(0);
                }

                break;
            default:
                break;
        }

    }


    private bool ConnectServerStart()
    {
        if (hostName != "localhost")
        {
            return ConnectHostStart(hostName, hostPort);
        }
        else
        {
            return ConnectIpStart("127.0.0.1", hostPort);
        }
    }

    private bool serverRuning = true;

    private void ThreadBackGround()
    {
        while (serverRuning)
        {
            try
            {
                if (clientSocket == null || clientSocket.Connected == false)
                {
                    if (!ConnectServerStart())
                    {
                        Thread.Sleep(3000);
                        continue;
                    }
                }
                checkToServerMessageList();

            }
            catch (Exception ex)
            {
                Debug.LogError(ex.ToString());
            }
            Thread.Sleep(10);
        }
    }
    private void checkToServerMessageList()
    {
        for (int i = 0; i < msToServerList.Count; i++)
        {
            MemoryStream ms = null;
            lock (msToServerList)
            {
                ms = msToServerList.Dequeue();
            }
            byte[] buff = ms.ToArray();

            SendToServer(buff);
        }
    }

    Queue<MemoryStream> msToServerList = new Queue<MemoryStream>();
    void SendToServer(MemoryStream ms)
    {
        if (clientSocket != null && clientSocket.Connected)
        {
            lock (msToServerList)
            {
                msToServerList.Enqueue(ms);
            }
        }
    }
    void SendToServer(byte[] buffer)
    {
        if (clientSocket != null && clientSocket.Connected)
        {
            try
            {
                int n = 0, sn = 0;
                do
                {
                    n = clientSocket.Send(buffer, sn, buffer.Length - sn, SocketFlags.None);
                    if (n > 0)
                    {
                        sn += n;
                        if (sn < buffer.Length)
                        {
                            Debug.LogError("发送数据不完整：" + sn + "/" + buffer.Length);
                        }
                    }
                    else
                    {
                        Debug.LogWarning("发送失败: " + n);
                        clientSocket.Close();
                        break;
                    }

                } while (n > 0 && buffer.Length > sn);
            }
            catch (Exception ex)
            {
                Debug.LogWarning(ex.Message);
            }
        }
    }

    void OnApplicationQuit()
    {
        serverRuning = false;
    }
}